<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Transformations</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="cairo, graphics, C, 2D vector library, Transformations, matrix">
<meta name="description" content="In this chapter of the Cairo graphics tutorial,
we will do wome transformations.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Transformations</h1>


<p>
In this part of the Cairo graphics programming tutorial, we will 
talk about transformations.
</p>

<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 

<p>
<b>An affine transform</b> is composed of zero or more linear transformations 
(rotation, scaling or shear) and translation (shift). Several linear transformations 
can be combined into a single matrix.
A <b>rotation</b> is a transformation that moves a rigid body around a fixed point.
A <b>scaling</b> is a transformation that enlarges or diminishes objects. 
The scale factor is the same in all directions.
A <b>translation</b> is a transformation that moves every point a constant 
distance in a specified direction.
A <b>shear</b> is a transformation that moves an object perpendicular to a
given axis, with greater value on one side of the axis than the other.
</p>

<p>
sources: (wikipedia.org, freedictionary.com)
</p>

<h2>Translation</h2>

<p>
The following example describes a simple translation.
</p>

<pre class="code">
static void do_drawing(cairo_t *cr)
{ 
  cairo_set_source_rgb(cr, 0.2, 0.3, 0.8);
  cairo_rectangle(cr, 10, 10, 30, 30);
  cairo_fill(cr);

  cairo_translate(cr, 20, 20);
  cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
  cairo_rectangle(cr, 0, 0, 30, 30);
  cairo_fill(cr);
  
  cairo_translate(cr, 30, 30);
  cairo_set_source_rgb(cr, 0.8, 0.8, 0.2);
  cairo_rectangle(cr, 0, 0, 30, 30);
  cairo_fill(cr);
  
  cairo_translate(cr, 40, 40);
  cairo_set_source_rgb(cr, 0.3, 0.8, 0.8);
  cairo_rectangle(cr, 0, 0, 30, 30);
  cairo_fill(cr);    
}
</pre>

<p>
The examle draws a rectangle. Then we do a translation and 
draw the same rectangle again.
</p>

<pre class="explanation">
cairo_translate(cr, 20, 20);
</pre>

<p>
The <code>cairo_translate()</code> function modifies the current transormation 
matrix by tranlating the user space origin. In our case we shift the origin by 
20 units in both directions.
</p>

<img src="/img/gfx/cairoc/translation.png" alt="Translation">
<div class="figure">Figure: Translation</div>


<h2>Shear</h2>

<p>
In the following example, we perform a shearing operation. A shearing is an 
object distortion along a particular axis. There is no shear function for this 
operation. We need to create our own transformation matrix. Note that each 
affine transformation can be performed by creating a transformation matrix.
</p>

<pre class="code">
static void do_drawing(cairo_t *cr)
{  
  cairo_matrix_t matrix;

  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  cairo_rectangle(cr, 20, 30, 80, 50);
  cairo_fill(cr);
  cairo_matrix_init(&amp;matrix,
      1.0, 0.5,
      0.0, 1.0,
      0.0, 0.0);

  cairo_transform(cr, &amp;matrix);
  cairo_rectangle(cr, 130, 30, 80, 50);
  cairo_fill(cr);
}
</pre>

<p>
In this code example, we perform a simple shearing operation.
</p>

<pre class="explanation">
cairo_matrix_t matrix;
</pre>

<p>
The <code>cairo_matrix_t</code> is a structure that holds an affine transformation.
</p>

<pre class="explanation">
cairo_matrix_init(&amp;matrix,
    1.0, 0.5,
    0.0, 1.0,
    0.0, 0.0);
</pre>

<p>
This transformation shears y values by 0.5 of the x values.
</p>

<pre class="explanation">
cairo_transform(cr, &amp;matrix);
</pre>

<p>
We perform the transformation with the transform() method.
</p>

<img src="/img/gfx/cairoc/shearing.png" alt="Shearing">
<div class="figure">Figure: Shearing</div>


<h2>Scaling</h2>

<p>
The next example demonstrates a scaling operation. Scaling is a transformation 
operation where the object is enlarged or shrinken.
</p>

<pre class="code">
static void do_drawing(cairo_t *cr)
{        
  cairo_set_source_rgb(cr, 0.2, 0.3, 0.8);
  cairo_rectangle(cr, 10, 10, 90, 90);    
  cairo_fill(cr);
  
  cairo_scale(cr, 0.6, 0.6);
  cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
  cairo_rectangle(cr, 30, 30, 90, 90);    
  cairo_fill(cr);  

  cairo_scale(cr, 0.8, 0.8);
  cairo_set_source_rgb(cr, 0.8, 0.8, 0.2);
  cairo_rectangle(cr, 50, 50, 90, 90);    
  cairo_fill(cr);      
}
</pre>

<p>
We draw three rectangles of 90x90px size. On two of them, we perform 
a scaling operation.
</p>

<pre class="explanation">
cairo_scale(cr, 0.6, 0.6);
cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
cairo_rectangle(cr, 30, 30, 90, 90);    
cairo_fill(cr);  
</pre>

<p>
We uniformly scale a rectangle by a factor of 0.6.
</p> 

<pre class="explanation">
cairo_scale(cr, 0.8, 0.8);
cairo_set_source_rgb(cr, 0.8, 0.8, 0.2);
cairo_rectangle(cr, 50, 50, 90, 90);    
cairo_fill(cr); 
</pre>

<p>
Here we perform another scaling operation by a factor of 0.8. If we look 
at the picture, we see, that the third yellow rectangle is the smallest 
one. Even if we have used a smaller scaling factor. This is because 
transformation operations are additive. In fact, the third rectangle was 
scaled by a factor of 0.528 (0.6x0.8).
</p>

<img src="/img/gfx/cairoc/scaling.png" alt="Scaling">
<div class="figure">Figure: Scaling</div>


<h2>Isolating transformations</h2>

<p>
Transformation operations are additive. To isolate one operation from
the other one, we can use the <code>cairo_save()</code> and <code>cairo_restore()</code>
functions. The <code>cairo_save()</code> function makes a copy of the current state of the
drawing context and saves it on an internal stack of saved states. The <code>cairo_restore()</code> 
function will re-establish the context to the saved state.
</p>

<pre class="code">
static void do_drawing(cairo_t *cr)
{     
  cairo_set_source_rgb(cr, 0.2, 0.3, 0.8);
  cairo_rectangle(cr, 10, 10, 90, 90);    
  cairo_fill(cr);
  
  cairo_save(cr);
  cairo_scale(cr, 0.6, 0.6);
  cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
  cairo_rectangle(cr, 30, 30, 90, 90);    
  cairo_fill(cr);
  cairo_restore(cr);

  cairo_save(cr);
  cairo_scale(cr, 0.8, 0.8);
  cairo_set_source_rgb(cr, 0.8, 0.8, 0.2);
  cairo_rectangle(cr, 50, 50, 90, 90);    
  cairo_fill(cr);        
  cairo_restore(cr);
}
</pre>

<p>
In the example we scale two rectangles. This time we isolate the 
scaling operations from each other.
</p>

<pre class="explanation">
cairo_save(cr);
cairo_scale(cr, 0.6, 0.6);
cairo_set_source_rgb(cr, 0.8, 0.3, 0.2);
cairo_rectangle(cr, 30, 30, 90, 90);    
cairo_fill(cr);
cairo_restore(cr);
</pre>

<p>
We isolate the scaling operation by putting the <code>cairo_scale()</code>
function between the <code>cairo_save()</code> and <code>cairo_restore()</code> 
functions.
</p>

<img src="/img/gfx/cairoc/isolation.png" alt="Isolating transformations">
<div class="figure">Figure: Isolating transformations</div>

<p>
Now the third yellow rectangle is bigger than the second red one.
</p>


<h2>Donut</h2>

<p>
In the following example we create an complex shape by 
rotating a bunch of ellipses.
</p>


<pre class="code">
#include &lt;cairo.h&gt;
#include &lt;gtk/gtk.h&gt;
#include &lt;math.h&gt;


static void do_drawing(cairo_t *, GtkWidget *widget);

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{      
  cr = gdk_cairo_create(gtk_widget_get_window(widget));
  do_drawing(cr, widget);
  cairo_destroy(cr);

  return FALSE;
}

static void do_drawing(cairo_t *cr, GtkWidget *widget)
{         
  GtkWidget *win = gtk_widget_get_toplevel(widget);
  
  gint width, height;
  gtk_window_get_size(GTK_WINDOW(win), &amp;width, &amp;height);

  cairo_set_line_width(cr, 0.5);
  cairo_translate(cr, width/2, height/2);
  cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
  cairo_stroke(cr);

  gint i;
  for (i = 0; i &lt; 36; i++) {
      cairo_save(cr);
      cairo_rotate(cr, i*M_PI/36);
      cairo_scale(cr, 0.3, 1);
      cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
      cairo_restore(cr);
      cairo_stroke(cr);      
  }    
}


int main(int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *darea;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  darea = gtk_drawing_area_new();
  gtk_container_add(GTK_CONTAINER (window), darea);

  g_signal_connect(G_OBJECT(darea), "draw", 
      G_CALLBACK(on_draw_event), NULL);
  g_signal_connect(G_OBJECT(window), "destroy",
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 350, 250); 
  gtk_window_set_title(GTK_WINDOW(window), "Donut");
  
  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
We will do rotation and scaling operations. We will also save and restore Cairo contexts.
</p>

<pre class="explanation">
cairo_translate(cr, width/2, height/2);
cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
cairo_stroke(cr);
</pre>

<p>
In the middle of the GTK+ window, we create a circle. This 
will be a bounding circle for our ellipses.
</p>

<pre class="explanation">
gint i;
for (i = 0; i &lt; 36; i++) {
    cairo_save(cr);
    cairo_rotate(cr, i*M_PI/36);
    cairo_scale(cr, 0.3, 1);
    cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI);
    cairo_restore(cr);
    cairo_stroke(cr);      
}   
</pre>

<p>
We create 36 ellipses along the path of our bounding circle. We insulate each 
rotate and scale operation from one another with the <code>cairo_save()</code> and 
<code>cairo_restore()</code> methods.
</p>


<h2>Star</h2>

<p>
The next example shows a rotating and scaling star.
</p>

<pre class="code">
#include &lt;cairo.h&gt;
#include &lt;gtk/gtk.h&gt;

static void do_drawing(cairo_t *, GtkWidget *widget);

int points[11][2] = { 
    { 0, 85 }, 
    { 75, 75 }, 
    { 100, 10 }, 
    { 125, 75 }, 
    { 200, 85 },
    { 150, 125 }, 
    { 160, 190 },
    { 100, 150 }, 
    { 40, 190 },
    { 50, 125 },
    { 0, 85 } 
};

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{      
  cr = gdk_cairo_create(gtk_widget_get_window(widget));
  do_drawing(cr, widget);
  cairo_destroy(cr);

  return FALSE;
}

static void do_drawing(cairo_t *cr, GtkWidget *widget)
{
  static gdouble angle = 0;
  static gdouble scale = 1;
  static gdouble delta = 0.01;

  GtkWidget *win = gtk_widget_get_toplevel(widget);
  
  gint width, height;
  gtk_window_get_size(GTK_WINDOW(win), &amp;width, &amp;height);

  cairo_set_source_rgb(cr, 0, 0.44, 0.7);
  cairo_set_line_width(cr, 1);

  cairo_translate(cr, width/2, height/2 );
  cairo_rotate(cr, angle);
  cairo_scale(cr, scale, scale);

  gint i;

  for ( i = 0; i &lt; 10; i++ ) {
      cairo_line_to(cr, points[i][0], points[i][1]);
  }

  cairo_close_path(cr);
  cairo_fill(cr);
  cairo_stroke(cr);

  if ( scale &lt; 0.01 ) {
      delta = -delta;
  } else if (scale > 0.99) {
      delta = -delta;
  }

  scale += delta;
  angle += 0.01;    
}

static gboolean time_handler(GtkWidget *widget)
{
  gtk_widget_queue_draw(widget);
  
  return TRUE;
}


int main(int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *darea;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  
  darea = gtk_drawing_area_new();
  gtk_container_add(GTK_CONTAINER (window), darea);  

  g_signal_connect(G_OBJECT(darea), "draw", 
      G_CALLBACK(on_draw_event), NULL); 
  g_signal_connect(window, "destroy",
      G_CALLBACK(gtk_main_quit), NULL);
 
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); 
  gtk_window_set_title(GTK_WINDOW(window), "Star");

  g_timeout_add(10, (GSourceFunc) time_handler, (gpointer) window);  

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
In this example, we create a star object. We will translate it, rotate it and scale it. 
</p>

<pre class="explanation">
int points[11][2] = { 
    { 0, 85 }, 
    { 75, 75 }, 
    { 100, 10 }, 
...
</pre>

<p>
The star object will be constructed from these points.
</p>

<pre class="explanation">
static gdouble angle = 0;
static gdouble scale = 1;
static gdouble delta = 0.01;
</pre>

<p>
We initialize three important variables. The angle is used in the rotation, the 
scale in scaling the star object. The delta variable controls when the star is
 growing and when it is shrinking.
</p>

<pre class="explanation">
cairo_translate(cr, width/2, height/2);
cairo_rotate(cr, angle);
cairo_scale(cr, scale, scale);
</pre>

<p>
We shift the star into the middle of the window. Rotate it and scale it.
</p>

<pre class="explanation">
gint i;
for ( i = 0; i &lt; 10; i++ ) {
    cairo_line_to(cr, points[i][0], points[i][1]);
}

cairo_close_path(cr);
cairo_fill(cr);
cairo_stroke(cr);
</pre>

<p>
Here we draw the star object.
</p>

<pre class="explanation">
if ( scale &lt; 0.01 ) {
    delta = -delta;
} else if (scale &gt; 0.99) {
    delta = -delta;
}
</pre>

<p>
These lines control the growing or shrinking of the star object.
</p>

<p>
In this part of the Cairo graphics tutorial, we talked about transformations.
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified December 13, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>


